import os
import json
from datetime import datetime
from typing import List, Dict
from django.conf import settings
from django.template.loader import render_to_string
from django.utils import timezone
from django.template.loader import get_template
from django.http import HttpResponse
from reportlab.lib import colors
from reportlab.lib.pagesizes import A4
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import inch
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
from ..models import TestExecution, TestReport, Project


class ReportGenerator:
    """测试报告生成器"""
    
    def __init__(self, project: Project, executions: List[TestExecution]):
        self.project = project
        self.executions = executions
        self.start_time = min(exe.start_time for exe in executions if exe.start_time)
        self.end_time = max(exe.end_time for exe in executions if exe.end_time)
        self._register_fonts()
        self.styles = getSampleStyleSheet()
        self._create_custom_styles()
        
    def _register_fonts(self):
        """注册中文字体"""
        try:
            # 注册微软雅黑字体（请确保字体文件存在）
            font_path = "C:/Windows/Fonts/msyh.ttc"
            pdfmetrics.registerFont(TTFont('MicrosoftYaHei', font_path))
        except:
            # 如果注册失败，使用默认字体
            pass

    def _create_custom_styles(self):
        """创建自定义样式"""
        self.styles.add(ParagraphStyle(
            name='ChineseTitle',
            fontName='MicrosoftYaHei' if 'MicrosoftYaHei' in pdfmetrics.getRegisteredFontNames() else 'Helvetica',
            fontSize=16,
            leading=20,
            alignment=1  # 居中对齐
        ))
        self.styles.add(ParagraphStyle(
            name='ChineseBody',
            fontName='MicrosoftYaHei' if 'MicrosoftYaHei' in pdfmetrics.getRegisteredFontNames() else 'Helvetica',
            fontSize=10,
            leading=14
        ))

    def generate_summary(self) -> Dict:
        """生成测试结果统计"""
        total = len(self.executions)
        passed = sum(1 for exe in self.executions if exe.result == 'pass')
        failed = sum(1 for exe in self.executions if exe.result == 'fail')
        error = sum(1 for exe in self.executions if exe.result == 'error')
        skipped = sum(1 for exe in self.executions if exe.result == 'skip')
        
        return {
            'total_cases': total,
            'passed_cases': passed,
            'failed_cases': failed,
            'error_cases': error,
            'skipped_cases': skipped,
            'pass_rate': f"{(passed / total * 100):.2f}%" if total > 0 else "0%"
        }
        
    def generate_execution_details(self) -> List[Dict]:
        """生成执行详情"""
        details = []
        for execution in self.executions:
            detail = {
                'case_name': execution.test_case.name,
                'interface': execution.test_case.interface.name,
                'status': execution.status,
                'result': execution.result,
                'start_time': execution.start_time.strftime('%Y-%m-%d %H:%M:%S') if execution.start_time else '',
                'end_time': execution.end_time.strftime('%Y-%m-%d %H:%M:%S') if execution.end_time else '',
                'duration': (execution.end_time - execution.start_time).total_seconds() if execution.start_time and execution.end_time else 0,
                'error_message': execution.error_message,
                'request_data': execution.request_data,
                'response_data': execution.response_data,
            }
            details.append(detail)
        return details
        
    def generate_html_report(self) -> str:
        """生成HTML格式的测试报告"""
        context = {
            'project_name': self.project.name,
            'summary': self.generate_summary(),
            'execution_details': self.generate_execution_details(),
            'start_time': self.start_time.strftime('%Y-%m-%d %H:%M:%S'),
            'end_time': self.end_time.strftime('%Y-%m-%d %H:%M:%S'),
            'duration': (self.end_time - self.start_time).total_seconds(),
            'generated_time': timezone.now().strftime('%Y-%m-%d %H:%M:%S')
        }
        
        return render_to_string('api_manager/report_template.html', context)
        
    def generate_json_report(self) -> Dict:
        """生成JSON格式的测试报告"""
        return {
            'project_name': self.project.name,
            'summary': self.generate_summary(),
            'execution_details': self.generate_execution_details(),
            'start_time': self.start_time.strftime('%Y-%m-%d %H:%M:%S'),
            'end_time': self.end_time.strftime('%Y-%m-%d %H:%M:%S'),
            'duration': (self.end_time - self.start_time).total_seconds(),
            'generated_time': timezone.now().strftime('%Y-%m-%d %H:%M:%S')
        }
        
    def generate_pdf_report(self, output_path):
        """生成PDF报告"""
        doc = SimpleDocTemplate(
            output_path,
            pagesize=A4,
            rightMargin=72,
            leftMargin=72,
            topMargin=72,
            bottomMargin=72
        )

        # 存储所有要添加到PDF的元素
        elements = []

        # 添加标题
        title = Paragraph(f"API测试报告 - {self.project.name}", self.styles['ChineseTitle'])
        elements.append(title)
        elements.append(Spacer(1, 20))

        # 添加基本信息表格
        basic_info = [
            ['项目名称', self.project.name],
            ['创建时间', self.start_time.strftime('%Y-%m-%d %H:%M:%S')],
            ['执行时间', self.end_time.strftime('%Y-%m-%d %H:%M:%S')],
            ['总用例数', self.generate_summary()['total_cases']],
            ['通过用例数', self.generate_summary()['passed_cases']],
            ['失败用例数', self.generate_summary()['failed_cases']],
            ['错误用例数', self.generate_summary()['error_cases']],
            ['跳过用例数', self.generate_summary()['skipped_cases']],
            ['通过率', self.generate_summary()['pass_rate']]
        ]

        basic_info_table = Table(basic_info, colWidths=[2*inch, 4*inch])
        basic_info_table.setStyle(TableStyle([
            ('FONTNAME', (0, 0), (-1, -1), 'MicrosoftYaHei' if 'MicrosoftYaHei' in pdfmetrics.getRegisteredFontNames() else 'Helvetica'),
            ('FONTSIZE', (0, 0), (-1, -1), 10),
            ('GRID', (0, 0), (-1, -1), 1, colors.black),
            ('BACKGROUND', (0, 0), (0, -1), colors.lightgrey),
            ('ALIGN', (0, 0), (-1, -1), 'CENTER'),
            ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
        ]))
        elements.append(basic_info_table)
        elements.append(Spacer(1, 20))

        # 添加执行详情
        elements.append(Paragraph("执行详情", self.styles['ChineseTitle']))
        elements.append(Spacer(1, 10))

        for execution in self.executions:
            # 用例基本信息
            case_info = [
                ['用例名称', execution.test_case.name],
                ['接口', execution.test_case.interface.name],
                ['执行结果', execution.result],
                ['执行时间', f"{execution.duration:.2f}s"]
            ]

            case_table = Table(case_info, colWidths=[2*inch, 4*inch])
            case_table.setStyle(TableStyle([
                ('FONTNAME', (0, 0), (-1, -1), 'MicrosoftYaHei' if 'MicrosoftYaHei' in pdfmetrics.getRegisteredFontNames() else 'Helvetica'),
                ('FONTSIZE', (0, 0), (-1, -1), 10),
                ('GRID', (0, 0), (-1, -1), 1, colors.black),
                ('BACKGROUND', (0, 0), (0, -1), colors.lightgrey),
                ('ALIGN', (0, 0), (-1, -1), 'LEFT'),
                ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
            ]))
            elements.append(case_table)
            elements.append(Spacer(1, 10))

            # 请求数据
            elements.append(Paragraph("请求数据:", self.styles['ChineseBody']))
            request_data = json.dumps(execution.request_data, ensure_ascii=False, indent=2)
            elements.append(Paragraph(f"<pre>{request_data}</pre>", self.styles['Code']))
            elements.append(Spacer(1, 10))

            # 响应数据
            elements.append(Paragraph("响应数据:", self.styles['ChineseBody']))
            response_data = json.dumps(execution.response_data, ensure_ascii=False, indent=2)
            elements.append(Paragraph(f"<pre>{response_data}</pre>", self.styles['Code']))
            elements.append(Spacer(1, 10))

            # 如果有错误信息
            if execution.error_message:
                elements.append(Paragraph("错误信息:", self.styles['ChineseBody']))
                elements.append(Paragraph(execution.error_message, self.styles['Code']))
                elements.append(Spacer(1, 10))

            elements.append(Spacer(1, 20))

        # 生成PDF
        doc.build(elements)
        
    def save_report(self, name: str = None) -> TestReport:
        """保存测试报告到数据库"""
        summary = self.generate_summary()
        
        report = TestReport.objects.create(
            name=name or f"{self.project.name}-测试报告-{timezone.now().strftime('%Y%m%d%H%M%S')}",
            project=self.project,
            creator=self.project.creator,
            start_time=self.start_time,
            end_time=self.end_time,
            total_cases=summary['total_cases'],
            passed_cases=summary['passed_cases'],
            failed_cases=summary['failed_cases'],
            error_cases=summary['error_cases'],
            skipped_cases=summary['skipped_cases'],
            summary=json.dumps(self.generate_json_report(), ensure_ascii=False, indent=2)
        )
        
        # 关联执行记录
        report.executions.set(self.executions)
        
        return report
        
    def export_html(self, output_dir: str = None) -> str:
        """导出HTML报告"""
        if not output_dir:
            output_dir = os.path.join(settings.MEDIA_ROOT, 'reports', 'html')
        os.makedirs(output_dir, exist_ok=True)
        
        filename = f"{self.project.name}-测试报告-{timezone.now().strftime('%Y%m%d%H%M%S')}.html"
        filepath = os.path.join(output_dir, filename)
        
        with open(filepath, 'w', encoding='utf-8') as f:
            f.write(self.generate_html_report())
            
        return filepath
        
    def export_json(self, output_dir: str = None) -> str:
        """导出JSON报告"""
        if not output_dir:
            output_dir = os.path.join(settings.MEDIA_ROOT, 'reports', 'json')
        os.makedirs(output_dir, exist_ok=True)
        
        filename = f"{self.project.name}-测试报告-{timezone.now().strftime('%Y%m%d%H%M%S')}.json"
        filepath = os.path.join(output_dir, filename)
        
        with open(filepath, 'w', encoding='utf-8') as f:
            json.dump(self.generate_json_report(), f, ensure_ascii=False, indent=2)
            
        return filepath
        
    def export_pdf(self, output_dir: str = None) -> str:
        """导出PDF报告"""
        if not output_dir:
            output_dir = os.path.join(settings.MEDIA_ROOT, 'reports', 'pdf')
        os.makedirs(output_dir, exist_ok=True)
        
        timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
        filename = f"test_report_{timestamp}.pdf"
        output_path = os.path.join(output_dir, filename)
        
        self.generate_pdf_report(output_path)
        return output_path 